package runtime

import (
	"context"
	"errors"
	"fmt"
	"gitee.com/Luna-CY/hui-hui/internal/util/network"
	"gitee.com/Luna-CY/hui-hui/internal/util/syscall"
	"net"
)

// CheckSystemHttpAndHttpsPort 检测系统的80与443端口
func CheckSystemHttpAndHttpsPort(ctx context.Context) error {
	var output, err = syscall.ExecuteCommandGetOutputIgnoreQuitCode(ctx, syscall.CommandQueryHttpAndHttpsPort[0], syscall.CommandQueryHttpAndHttpsPort[1:]...)
	if nil != err {
		return err
	}

	if 0 != len(output) {
		return errors.New("请检查系统80与443端口是否被占用")
	}

	return nil
}

// CheckSystemEnvironment 检查系统环境及资源是否满足启动需求
// 检查项:
//   - 系统80/443端口是否被占用
//   - 检查域名解析
func CheckSystemEnvironment(ctx context.Context, skipCheckHostname bool, hostname string) error {
	// 检查端口
	if err := CheckSystemHttpAndHttpsPort(ctx); nil != err {
		return err
	}

	if !skipCheckHostname {
		// 检查域名
		ipv4, ipv6, err := network.LookupHostname(ctx, hostname)
		if nil != err {
			return err
		}

		if (nil == ipv4 || ipv4.IsPrivate() || ipv4.IsLoopback()) && (nil == ipv6 || ipv6.IsPrivate() || ipv6.IsLoopback()) {
			return fmt.Errorf("域名[%s]未解析到有效的ipv4或ipv6地址，请域名解析配置或稍后重试", hostname)
		}

		// 本地网络接口列表
		addresses, err := net.InterfaceAddrs()
		if nil != err {
			return err
		}

		var find bool
		for _, address := range addresses {
			if in, ok := address.(*net.IPNet); ok && ((nil != ipv4 && in.IP.String() == ipv4.String()) || (nil != ipv6 && in.IP.String() == ipv6.String())) {
				find = true
				break
			}
		}

		if !find {
			if nil != ipv4 && nil != ipv6 {
				return fmt.Errorf("域名解析配置的地址[%s]或[%s]未在本地网络配置中发现", ipv4.String(), ipv6.String())
			}

			if nil != ipv4 {
				return fmt.Errorf("域名解析配置的地址[%s]未在本地网络配置中发现", ipv4.String())
			}

			if nil != ipv6 {
				return fmt.Errorf("域名解析配置的地址[%s]未在本地网络配置中发现", ipv6.String())
			}
		}
	}

	return nil
}
